package com.apache.security.filter;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.apache.security.SecurityConstant;
import com.apache.security.SecurityFilter;
import com.apache.security.util.SecurityHttpServletRequest;
import com.apache.security.util.SecurityHttpServletResponse;
import com.apache.security.util.XssUtil;
import com.apache.tools.StrUtil;

/**
 * 
 *
 */
public class DefaultBaseSecurityFilter implements Filter {

	private List<SecurityFilter> securityFilterList = new ArrayList<SecurityFilter>();
	private String errorPage;
	private String writeStr;
	private String encoding = null;

	public void destroy() {
		// TODO Auto-generated method stub
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException,
			ServletException {
		request.setCharacterEncoding(encoding);
		if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
			HttpServletRequest httpRequest = (HttpServletRequest) request;
			HttpServletResponse httpResponse = (HttpServletResponse) response;
			if (filterPath(httpRequest)) {
				filterChain.doFilter(request, response);
				return;
			}
			for (int i = 0; i < securityFilterList.size(); i++) {
				securityFilterList.get(i).setErrorPage(errorPage);
				int result = securityFilterList.get(i).doFilterInvoke(httpRequest, httpResponse);
				if (0 == result)
					return;
			}
			CookeHeader(httpRequest, httpResponse);
			filterChain.doFilter(new SecurityHttpServletRequest(httpRequest), new SecurityHttpServletResponse(
					httpResponse));
			//			if (null != httpRequest.getSession().getAttribute("randCode")) {
			//				httpRequest.getSession().setAttribute("randCode", httpRequest.getSession().getAttribute("randCode"));
			//			}
		} else {
			filterChain.doFilter(request, response);
		}
	}

	private boolean filterPath(HttpServletRequest httpRequest) {
		String path = StrUtil.doNull(httpRequest.getContextPath(), "/");
		String pui = httpRequest.getRequestURI();
		if (pui.contains(".css") || pui.contains(".js") || pui.contains("doService.action")) {
			//如果发现是css或者js文件，直接放行
			return true;
		}
		if (pui.endsWith("/")) {
			if (pui.endsWith(path + "/")) {
				return true;
			}
		} else {
			if (pui.endsWith(path)) {
				return true;
			}
		}
		if (null != writeStr) {
			if (writeStr.contains(pui)) {
				return true;
			}
		}
		return false;
	}

	public void init(FilterConfig filterConfig) throws ServletException {
		initRedictWhiteList(filterConfig);
		errorPage = filterConfig.getInitParameter("errorPage");
		writeStr = filterConfig.getInitParameter("writeStr");
		this.encoding = filterConfig.getInitParameter("encoding");
		if (XssUtil.isNull(this.encoding))
			this.encoding = "UTF-8";
		try {
			initSecurityFilterList(filterConfig);
		} catch (ClassNotFoundException e) {
			throw new ServletException(e);
		} catch (InstantiationException e) {
			throw new ServletException(e);
		} catch (IllegalAccessException e) {
			throw new ServletException(e);
		}
	}

	public void initRedictWhiteList(FilterConfig filterConfig) throws ServletException {
		String list = filterConfig.getInitParameter("redirectWhiteList");
		if (list == null || list.isEmpty()) {
			return;
		}
		String[] redirectWhiteList = list.split(",");
		List<Pattern> patterns = new ArrayList<Pattern>();
		for (String str : redirectWhiteList) {
			patterns.add(Pattern.compile(str));
		}
		SecurityConstant.redirectLocationWhiteList.addAll(patterns);
	}

	private void initSecurityFilterList(FilterConfig filterConfig) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException {
		String securityFilterS = filterConfig.getInitParameter("securityFilterList");
		if (securityFilterS == null || securityFilterS.isEmpty()) {
			return;
		}
		String[] filterList = securityFilterS.split(",");
		for (String filter : filterList) {
			Class securityFilter = Class.forName(filter);
			SecurityFilter securityFilterInstance = (SecurityFilter) securityFilter.newInstance();
			securityFilterList.add(securityFilterInstance);
		}
	}

	/**
	 * description:  修复会话cookie 中缺少HttpOnly属性漏洞
	 */
	private void CookeHeader(HttpServletRequest request, HttpServletResponse response) {
		Cookie[] cookies = request.getCookies();
		if (null != cookies) {
			Calendar cal = Calendar.getInstance();
			cal.add(Calendar.HOUR, 1);
			Date date = cal.getTime();
			Locale locale = Locale.CHINA;
			SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss", locale);
			for (int i = 0; i < cookies.length; i++) {
				Cookie cookie = cookies[i];
				if (null != cookie) {
					if ("JSESSIONID".equalsIgnoreCase(cookie.getName())) {
						StringBuilder builder = new StringBuilder();
						if (cookie.getSecure())
							builder.append("Secure;");
						String value = cookie.getValue();
						String path = request.getContextPath();
						builder.append("JSESSIONID=" + value + ";");
						builder.append("path=" + path + ";");
						builder.append("HttpOnly;");
						builder.append("Expires=" + sdf.format(date));
						response.addHeader("Set-Cookie", builder.toString());
					} else if ("apache_".equalsIgnoreCase(cookie.getName())) {
						StringBuilder builder = new StringBuilder();
						if (cookie.getSecure())
							builder.append("Secure;");
						String value = cookie.getValue();
						String path = request.getContextPath();
						builder.append("apache_=" + value + ";");
						builder.append("path=" + path + ";");
						builder.append("HttpOnly;");
						builder.append("Expires=" + sdf.format(date));
						response.addHeader("Set-Cookie", builder.toString());
					}
				}
			}
		}
	}

}
